' Copyright (c) Microsoft Corporation.  All rights reserved.
Imports System
Imports System.Collections.Generic
Imports System.Data
Imports System.Data.EntityClient
Imports System.Linq
Imports System.Runtime.CompilerServices
Imports System.Xml.Linq

Namespace EdmMetadataHelpersVB
    ''' <summary>
    ''' A class that allows a EntityDataReader to be converted to XML 
    ''' 
    ''' This is achieved by Yielding XElements for each IExtendedDataRecord in the reader
    ''' </summary>
    Public Class EdmXmlAdapter
        Public Shared Function GetElements(ByVal reader As EntityDataReader) As IEnumerable(Of XElement)
            Return GetElements(DirectCast(reader, IDataReader))
        End Function


        ''' <summary>
        ''' Converts an IExtendedDataRecord into an XElement
        ''' </summary>
        Private Shared Function CreateElement(ByVal record As IExtendedDataRecord) As XElement
            Dim definition As String = record.DataRecordInfo.RecordType.EdmType.FullName
            Dim name As String

            If definition.Contains("[") Then
                name = "Row"
            Else
                name = definition
            End If

            Dim root As XElement = New XElement(name)

            If definition <> name Then
                root.Add(New XAttribute("Definition", definition))
            End If

            root.Add(GetElements(record))

            Return root
        End Function
        ''' <summary>
        ''' Flattens a Cell of unknown type into either Rows, Row or a simple value
        ''' </summary>
        Private Shared Function GetData(ByVal obj As Object) As Object
            'If we implement IExtendedDataRecord we need to unpack

            If obj Is GetType(IExtendedDataRecord) Then
                'We might be a DataReader in which there are Rows
                If obj Is GetType(IDataReader) Then
                    Return New XElement("Rows", GetElements(CType(obj, IDataReader)))
                Else
                    Return CreateElement(CType(obj, IExtendedDataRecord))
                End If
            Else
                Return obj
            End If
        End Function
        ''' <summary>
        ''' Gets XElements for each IExtendDataRecord in the Reader
        ''' </summary>
        ''' <remarks>
        ''' This method is private because it is possible to call this without passing
        ''' in something that contains IExtendedDataRecord... If you do this an empty Enumeration 
        ''' will result. Since we can't create an XElement for standard implementations of IDataRecord.
        ''' </remarks>
        Private Shared Function GetElements(ByVal reader As IDataReader) As IEnumerable(Of XElement)
            Return From record In reader.Enumerate().OfType(Of IExtendedDataRecord)() _
                   Select CreateElement(record)
        End Function
        ''' <summary>
        ''' Gets XElements for each of the columns in the IExtendedDataRecord
        ''' </summary>
        Private Shared Function GetElements(ByVal record As IExtendedDataRecord) As IEnumerable(Of XElement)
            Return From field In record.DataRecordInfo.FieldMetadata _
                    Let fieldname = field.FieldType.Name _
                    Select New XElement(fieldname, GetData(record(fieldname)))
        End Function
    End Class
End Namespace

